package com.huawei.virest.action;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdom.JDOMException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.huawei.virest.common.SystemInit;
import com.huawei.virest.common.constant.Constants;
import com.huawei.virest.common.domain.HttpResp;
import com.huawei.virest.common.domain.MatchedResult;
import com.huawei.virest.common.util.HttpUtils;
import com.huawei.virest.common.util.Utils;
import com.huawei.virest.domain.StructuredData;

@Controller
public class VIRestAction
{
    /**
     * 日志工具类
     */
    private static Log logger = LogFactory.getLog(VIRestAction.class);
    
    private String path;
    
    private long startTime = 0L;
    
    private long endTime = 0L;
    
    /**
     * 结构化数据对象
     */
    private StructuredData structuredData;
    
    public VIRestAction()
    {
        
    }
    
    @RequestMapping(value = "/executeVIRest.html", method = RequestMethod.GET)
    public String executeVIRest(HttpServletRequest request, ModelMap modelMap)
            throws UnsupportedEncodingException
    {
        // 获取选择路径
        path = request.getParameter(Constants.PATH).trim();
        // 转码
        path = new String(path.getBytes(Constants.ISO8859_1), Constants.DEFAULT_ENCODING);
        
        // 读取结构化数据
        logger.info("读取结构化数据");
        readStructuredData();
        
        // 生成用例列表
        logger.info("生成用例列表");
        produceCaseList();
        
        // 数据驱动, 发送请求和解析响应
        logger.info("数据驱动, 发送请求和解析响应");
        // dataDriven();
        
        // 报告
        logger.info("报告");
        report(modelMap);
        
        return "index";
    }
    
    /**
     * 读取结构化数据
     * @param rootDir 根目录
     * @throws UnsupportedEncodingException 不支持的编码异常
     */
    private void readStructuredData()
            throws UnsupportedEncodingException
    {
        // 开始时间
        startTime = System.currentTimeMillis();
        
        // 获取用户选择的根目录    	
        if (Utils.isNull(path))
        {
            // 系统配置的默认路径
        	path = SystemInit.getConfig().getRootDir();
        }
        
        logger.info("选择脚本路径：" + path);
        File file = new File(path);
        
        structuredData = new StructuredData();
        structuredData.readStructuredData(file); // 读取结构化数据
    }
    
    /**
     * 解析请求脚本
     * 
     * @return void [返回类型说明]
     * @exception throws [违例类型] [违例说明]
     * @see [类、类#方法、类#成员]
     */
    private void produceCaseList()
    {
        Map<String, Map<String, Object>> caseList = new TreeMap<String, Map<String, Object>>();
        
        Map<String, File> rcqMap = structuredData.getRcqMap();
        
        Set<String> set = rcqMap.keySet();
        for (String key : set)
        {
            File file = rcqMap.get(key);
            Map<String, Object> requestData = structuredData.parseRequestData(file); // 解析请求数据
            caseList.put(key, requestData);
            
            executeCase(key, requestData);
        }
        
        structuredData.setCaseList(caseList);

		// 结束时间
        endTime = System.currentTimeMillis();
    }
    
    /**
     * 数据驱动, 执行脚本发送请求和解析响应
     * 
     * @return void [返回类型说明]
     * @exception throws [违例类型] [违例说明]
     * @see [类、类#方法、类#成员]
     */
    public void dataDriven()
    {
        // 获取执行脚本数据
        Map<String, Map<String, Object>> caseList = structuredData.getCaseList();
        
        Set<String> set = caseList.keySet();        
        for (String key : set)
        {
            Map<String, Object> requestData = caseList.get(key);
            if (requestData.size() > 0)
            {
                executeCase(key, requestData); // 执行用例
            }
        }

		// 结束时间
        endTime = System.currentTimeMillis();
    }
    
    /**
     * 执行用例
     * @param key 文件名
     * @param requestData 请求数据
     */
    private void executeCase(String key, Map<String, Object> requestData)
    {
        logger.info("执行用例：" + key);
        HttpResp resp = HttpUtils.getInstance().request(requestData); // 请求方法
        logger.info("执行用例：" + key + " 的响应结果为：" + resp.getResponse());
        structuredData.parseResponseData(key, resp); // 解析响应数据
    }
    
    /**
     * 报告
     * @param modelMap 模板Map
     */
    private void report(ModelMap modelMap)
    {
    	report(modelMap, structuredData.getResultMap());
    }
    
    /**
     * 报告
     * @param modelMap 模板Map
     */
    private void report(ModelMap modelMap, Map<String, MatchedResult> map)
    {
        // 文件路径
        modelMap.put(Constants.Report.FILE_PATH, path);
        // 总数
        modelMap.put(Constants.Report.TOTAL_COUNT, structuredData.getTotalCount());
        // 成功数
        modelMap.put(Constants.Report.SUCCESS_COUNT, structuredData.getSuccessCount());
        // 结果Map
        modelMap.put(Constants.Report.RESULT_MAP, map);
        // 运行总消耗时间
        modelMap.put(Constants.Report.EXPEND_TIME, consumeTime());
    }

	/**
	 * @return 运行消耗时间
	 */
	private String consumeTime() {        
        // 获取分钟
        long expendMinute = (endTime - startTime) / 1000 / 60;
        
        // 获取剩余秒数
        long expendSecs = (endTime - startTime) / 1000 % 60;
        
        StringBuffer expendTime = new StringBuffer("运行总消耗时间为：");
        
        if (expendMinute > 0)
        {
            expendTime.append(expendMinute + " 分");
        }
        expendTime.append(expendSecs + " 秒");
        
		return expendTime.toString();
	}
    
    /**
     * 查看比对结果
     * @param request 请求对象
     * @param modelMap modelMap
     * @return [参数说明]
     * 
     * @return String [返回类型说明]
     * @exception throws [违例类型] [违例说明]
     * @see [类、类#方法、类#成员]
     */
    @SuppressWarnings("unchecked")
    @RequestMapping(value = "/compareResult.html", method = RequestMethod.GET)
    public String compareResult(HttpServletRequest request, ModelMap modelMap)
    {
    	// 缩进
    	String indent = "&nbsp;&nbsp;&nbsp;&nbsp;";
    	String newLine = "<br>";
        
        // 获取响应结果
        String key = request.getParameter(Constants.CompareResult.RESULT_KEY);
        
        // 获取响应对象
        MatchedResult result = structuredData.getResultMap().get(key);
        
        // 执行的脚本
        Map<String, Object> requestData = structuredData.getCaseList().get(key);
        modelMap.put(Constants.PATH, structuredData.getRcqMap().get(key).getPath());
        
        if (requestData.size() > 0)
        {
            modelMap.put(Constants.CompareResult.URL, requestData.get(Constants.URL).toString());
            modelMap.put(Constants.METHOD, requestData.get(Constants.METHOD).toString());
            
            StringBuffer headers = new StringBuffer();
            
            Map<String, String> headerValues = (Map<String, String>)requestData.get(Constants.HEADERS);
            Set<String> set = headerValues.keySet();
            for (String name : set)
            {
                headers.append(name)
                        .append(":")
                        .append(headerValues.get(name))
                        .append(newLine);
            }
            
            modelMap.put(Constants.HEADERS, headers.toString());
            if (null != requestData.get(Constants.BODY))
            {
                modelMap.put(Constants.BODY, requestData.get(Constants.BODY).toString());
            }
            if (null != requestData.get(Constants.ATTACHMENT))
            {
                modelMap.put(Constants.ATTACHMENT, requestData.get(Constants.ATTACHMENT).toString());
            }
        }
        
        // 获取预期结果
        String expextResult = null;
        
        if (structuredData.getRcsMap().get(key) != null)
        {
            try
            {
                File file = structuredData.getRcsMap().get(key);
                expextResult = Utils.formatXML(file, Constants.DEFAULT_ENCODING, indent, newLine);
                expextResult = newLine + Utils.escapeNewLine(expextResult);
            }
            catch (IOException e)
            {
                expextResult = "读取响应XML文件错误:" + e.getMessage();
            }
            catch (JDOMException e)
            {
                expextResult = "响应XML文件编写错误:" + e.getMessage();
            }
        }
        else
        {
            expextResult = "响应结果匹配文件不存在";
        }
        modelMap.put(Constants.CompareResult.EXPECT_RESULT, expextResult);

        // 获取响应结果
        String response = Utils.formatJSON(result.getResponse(), indent, newLine);
        modelMap.put(Constants.CompareResult.RESPONSE, Utils.escapeNewLine(response));
        modelMap.put(Constants.CompareResult.MESSAGE, result.getMsg());
        
        return "compareResult";
    }
    
    @RequestMapping(value = "/searchInterface.html", method = RequestMethod.GET)
    public String searchInterface(HttpServletRequest request, ModelMap modelMap)
    {
    	String interfaceName = request.getParameter("interfaceName");
    	String resultType = request.getParameter("resultType");
        
        Map<String, MatchedResult> searchMap = new TreeMap<String, MatchedResult>();
        Map<String, MatchedResult> resultMap = structuredData.getResultMap();
        
        boolean flag = false;
        Set<String> keySet = resultMap.keySet();
        for (String key : keySet) {
        	flag = false;
			if (interfaceName != null && key.toLowerCase().contains(interfaceName.toLowerCase()))
			{
				flag = true;
			}
			if (resultType != null && resultMap.get(key).getFlag().equals(resultType))
			{
				flag = true;
			}
			
			if (flag)
			{
				searchMap.put(key, resultMap.get(key));
			}
		}
        
        report(modelMap, searchMap);      
        
        return "index";
    }
    
}
